﻿using Volo.Abp.Reflection;

namespace CTP.CRM.Core.Helper
{
    public static class EnumHelper
    {
        /// <summary>
        /// 获取二进制枚举实例 由 哪些项组成
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="originBitEnum"></param>
        /// <returns></returns>
        public static List<int> GetBitEnumValues<T>(T originBitEnum) where T : Enum
        {
            List<int> result = new List<int>();
            var attribute = ReflectionHelper.GetSingleAttributeOrDefault<FlagsAttribute>(originBitEnum.GetType());
            if (attribute is null) return result;

            var OriginBitEnumValue = Convert.ToInt32(originBitEnum);
            foreach (int EnumItemValue in Enum.GetValues(typeof(T)))
            {
                if ((OriginBitEnumValue & EnumItemValue) == EnumItemValue)
                {
                    result.Add(EnumItemValue);
                }
            }
            return result;
        }

        /// <summary>
        /// 获取枚举类型的所有值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="tType"></param>
        /// <returns></returns>
        public static List<int> GetEnumTypeValueList<T>() where T : Enum
        {
            //List<int> result = new List<int>();
            //if (tType == typeof(T))
            //{
            //    resList = Enum.GetValues(typeof(T)).OfType<T>().ToList().ConvertAll<int>(x => Convert.ToInt32(x));
            //}

            //return resList;

            //已经协定T的类型并且 对T取值 ，不需要再传参数了
            var tranResult = Enum.GetValues(typeof(T)).OfType<T>().ToList();
            return tranResult.ConvertAll<int>(x => Convert.ToInt32(x));
        }

        /// <summary>
        /// 反解枚举类型
        /// </summary>
        /// <param name="enumType"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static List<T> InverseEnumList<T>(this T? enumType) where T : struct, Enum
        {
            if (enumType is null) return new List<T>();
            return Enum.GetValues<T>()
                .Where(val => enumType.Value.HasFlag(val))
                .ToList();
        }

        /// <summary>
        /// 反解枚举类型
        /// </summary>
        /// <param name="enumType"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static List<T> InverseEnumList<T>(this T enumType) where T : struct, Enum
        {
            return Enum.GetValues<T>()
                .Where(val => enumType.HasFlag(val))
                .ToList();
        }

        public static T BitwiseOr<T>(this IEnumerable<T> values) where T : Enum
        {
            if (values == null)
                throw new ArgumentNullException(nameof(values));

            // 获取枚举类型的底层类型
            Type underlyingType = Enum.GetUnderlyingType(typeof(T));

            // 初始化结果值
            dynamic result = Activator.CreateInstance(underlyingType);

            foreach (T value in values)
            {
                dynamic dynamicValue = Convert.ChangeType(value, underlyingType);
                result |= dynamicValue;
            }

            // 将最终结果转换回枚举类型
            return (T)Enum.ToObject(typeof(T), result);
        }

        public static T? BitwiseOr<T>(this IEnumerable<T?> values) where T : struct, Enum
        {
            if (values == null)
                throw new ArgumentNullException(nameof(values));

            // 获取枚举类型的底层类型
            Type underlyingType = Enum.GetUnderlyingType(typeof(T));

            // 初始化结果值
            dynamic result = Activator.CreateInstance(underlyingType);
            bool hasValue = false;

            foreach (T? value in values)
            {
                if (value.HasValue)
                {
                    dynamic dynamicValue = Convert.ChangeType(value.Value, underlyingType);
                    result |= dynamicValue;
                    hasValue = true;
                }
            }

            // 如果没有任何值，则返回 null
            if (!hasValue)
                return null;

            // 将最终结果转换回枚举类型
            return (T)Enum.ToObject(typeof(T), result);
        }
    }
}
